package com.example.selector;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;

public class SelectorThread implements Runnable {

    private Selector selector;
    private SelectorThreadGroup stg;
    private LinkedBlockingQueue<Channel> lbq = new LinkedBlockingQueue<>();

    public SelectorThread(SelectorThreadGroup stg) {
        try {
            this.stg = stg;
            this.selector = Selector.open();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void run() {

        while (true) {
            try {
                int num = selector.select();

                if (num > 0) {
                    Set<SelectionKey> keys = selector.selectedKeys();
                    Iterator<SelectionKey> iter = keys.iterator();
                    while (iter.hasNext()) {
                        SelectionKey key = iter.next();
                        iter.remove();

                        if (key.isAcceptable()) {
                            System.out.println(Thread.currentThread().getName() + " 处理accept");
                            acceptHandler(key);

                        } else if (key.isReadable()) {
                            System.out.println(Thread.currentThread().getName() + " 处理read");
                            readHandler(key);
                        }


                    }

                }

                while (!lbq.isEmpty()) {
                    Channel channel = lbq.take();
                    if (channel instanceof ServerSocketChannel) {
                        System.out.println(Thread.currentThread().getName() + " 注册server");

                        ServerSocketChannel server = (ServerSocketChannel) channel;
                        server.register(selector, SelectionKey.OP_ACCEPT);

                    } else if (channel instanceof SocketChannel) {
                        System.out.println(Thread.currentThread().getName() + " 注册client");

                        SocketChannel client = (SocketChannel) channel;

                        ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
                        client.register(selector, SelectionKey.OP_READ, buffer);
                    }

                }

            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }


        }

    }

    private void readHandler(SelectionKey key) {
        SocketChannel client = (SocketChannel) key.channel();
        ByteBuffer buffer = (ByteBuffer) key.attachment();
        buffer.clear();

        try {
            while (true) {
                int read = client.read(buffer);
                if (read > 0) {
                    buffer.flip();
                    while (buffer.hasRemaining()) {
                        client.write(buffer);
                    }
                    buffer.clear();
                } else if (read == 0) {
                    break;
                } else {
                    client.close();
                    break;
                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void acceptHandler(SelectionKey key) {
        try {
            ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
            SocketChannel client = ssc.accept();
            client.configureBlocking(false);

            stg.register2SelectorV3(client);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    public Selector getSelector() {
        return selector;
    }

    public LinkedBlockingQueue<Channel> getLbq() {
        return lbq;
    }
}
